package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.base.Strings;
import com.lkd.common.VMSystem;
import com.lkd.config.TopicConfig;
import com.lkd.contract.TaskCompleteContract;
import com.lkd.dao.TaskDao;
import com.lkd.dao.TaskDetailsDao;
import com.lkd.emq.MqttProducer;
import com.lkd.emq.MqttService;
import com.lkd.entity.TaskDetailsEntity;
import com.lkd.entity.TaskEntity;
import com.lkd.feign.UserService;
import com.lkd.feign.VMService;
import com.lkd.http.vo.CancelTaskViewModel;
import com.lkd.http.vo.TaskDetailsViewModel;
import com.lkd.http.vo.TaskViewModel;
import com.lkd.service.TaskService;
import com.lkd.vo.Pager;
import com.lkd.vo.UserVO;
import com.lkd.vo.VmVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class TaskServiceImpl extends ServiceImpl<TaskDao,TaskEntity> implements TaskService{

@Autowired
private VMService vmService;

@Autowired
private RedisTemplate<String,Object> redisTemplate;

@Autowired
private TaskDetailsDao taskDetailsDao;

@Autowired
private UserService userService;
@Autowired
private TaskDao taskDao;

@Autowired
private MqttProducer mqttProducer;
    @Override
    public Pager<TaskEntity> search(Long pageIndex, Long pageSize, String innerCode, Integer userId, String taskCode, Integer status, Boolean isRepair, String start, String end) {
        Page<TaskEntity> page = new Page<>(pageIndex,pageSize);
        LambdaQueryWrapper<TaskEntity> qw = new LambdaQueryWrapper<>();
        if(!Strings.isNullOrEmpty(innerCode)){
            qw.eq(TaskEntity::getInnerCode,innerCode);
        }
        if(userId != null && userId > 0){
            qw.eq(TaskEntity::getUserId,userId);
        }
        if(!Strings.isNullOrEmpty(taskCode)){
            qw.like(TaskEntity::getTaskCode,taskCode);
        }
        if(status != null && status > 0){
            qw.eq(TaskEntity::getTaskStatus,status);
        }
        if(isRepair != null){
            if(isRepair){
                qw.ne(TaskEntity::getProductTypeId,VMSystem.TASK_TYPE_SUPPLY);
            }else {
                qw.eq(TaskEntity::getProductTypeId,VMSystem.TASK_TYPE_SUPPLY);
            }
        }
        if(!Strings.isNullOrEmpty(start) && !Strings.isNullOrEmpty(end)){
            qw
                    .ge(TaskEntity::getCreateTime,LocalDate.parse(start,DateTimeFormatter.ISO_LOCAL_DATE))
                    .le(TaskEntity::getCreateTime,LocalDate.parse(end,DateTimeFormatter.ISO_LOCAL_DATE));
        }
        //根据最后更新时间倒序排序
        qw.orderByDesc(TaskEntity::getUpdateTime);

        return Pager.build(this.page(page,qw));
    }

    /**
     * 新建工单
     *
     * @param taskViewModel
     */
    @Override
    public void add(TaskViewModel taskViewModel) {
        //检查及校验参数
        cheak(taskViewModel);
        //将taskViewModel中的内容部复制到实体类
        TaskEntity taskEntity = new TaskEntity();
        BeanUtils.copyProperties(taskViewModel, taskEntity);
        //生成工单编号
        String taskCode = createTaskCode();
        //判断是否需要补货
        if (taskViewModel.getDetails() != null || taskViewModel.getDetails().size() != 0) {
            //补货操作
            replenishment(taskViewModel.getDetails(), taskEntity.getTaskId());
        }
        //封装其他实体类的参数
        setparameter(taskEntity, taskCode);
        //保存到数据库
        taskDao.insert(taskEntity);
        //修改redis數據
        int scode = 1;
        updateredis(taskEntity,scode);
    }

    /**
     * 增加或者減少得分
     * @param taskEntity
     * @param scode
     */
    private void updateredis(TaskEntity taskEntity,Integer scode) {
        String data = LocalDate.now().plusDays(0).format(DateTimeFormatter.ofPattern("yyyyMMdd"));;
        //組合key
        UserVO user = userService.getUser(taskEntity.getUserId());
        String key ="lkd-user-service-redis"+data+user.getRegionId()+user.getRoleCode();
        redisTemplate.opsForZSet().incrementScore(key,taskEntity.getUserId(),scode);
    }

    /**
     * 接收工单
     *
     * @param taskId
     */
    @Override
    public void accept(Integer taskId) {
        TaskEntity taskEntity = taskDao.selectById(taskId);
        if (taskEntity.getTaskStatus()!=1)
        {
            throw new RuntimeException("非待办工单");
        }
        taskEntity.setTaskStatus(2);
        taskDao.updateById(taskEntity);
    }

    /**
     * 拒绝工单/取消工单
     *
     * @param cancel
     */
    @Override
    public TaskEntity cancel(CancelTaskViewModel cancel ,Integer taskId) {
        TaskEntity taskEntity = taskDao.selectById(taskId);
        //判断
        if (taskEntity.getTaskStatus()==3)
        {
            throw  new RuntimeException("该工单已取消/拒绝");
        }else if (taskEntity.getProductTypeId()==4)
        {
            throw new RuntimeException("该工单已完成");
        }
        taskEntity.setTaskStatus(3);
        taskEntity.setDesc(cancel.getDesc());

        taskDao.updateById(taskEntity);
        //修改redis得分
        int scode =-1;
        updateredis(taskEntity,scode);
        return taskEntity;

    }

    /**
     * 完成工单
     *
     * @param taskId
     */
    @Override
    public void complete(Integer taskId) {
        TaskEntity taskEntity = taskDao.selectById(taskId);
        if (taskEntity.getTaskStatus()==4)
        {
            throw new RuntimeException("该工单已完成");
        }
        taskEntity.setTaskStatus(4);
        taskDao.updateById(taskEntity);
        //判断工单状态
        if (taskEntity.getProductTypeId() ==VMSystem.TASK_TYPE_DEPLOY
                ||taskEntity.getProductTypeId()==VMSystem.VM_STATUS_REVOKE)
        {
            //撤机或者投放工单
            sendProduct(taskEntity);
        }else if(taskEntity.getProductTypeId() ==VMSystem.TASK_TYPE_SUPPLY)
        {
            //补货工单,发送修改状态
           savegoods(taskEntity);
        }
    }

    /**
     * 补货工单
     * @param taskEntity
     */
    private void savegoods(TaskEntity taskEntity) {
        TaskCompleteContract taskCompleteContract = new TaskCompleteContract();
        //设置售货机id
        taskCompleteContract.setInnerCode(taskEntity.getInnerCode());
        //设置工单类型
        taskCompleteContract.setTaskType(taskEntity.getProductTypeId());
        //发送消息
        try {
            mqttProducer.send(TopicConfig.VMS_SUPPLY_TOPIC,2,taskCompleteContract);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("协议异常");
        }
    }

    /**
     * 撤机或者投放工单
     * @param taskEntity
     */
    private void sendProduct(TaskEntity taskEntity) {
        TaskCompleteContract taskCompleteContract = new TaskCompleteContract();
        //设置发送的售货机编号
        taskCompleteContract.setInnerCode(taskEntity.getInnerCode());
        //设置工单类型
        taskCompleteContract.setTaskType(taskEntity.getProductTypeId());
        //发送消息
        try {
            mqttProducer.send(TopicConfig.VMS_COMPLETED_TOPIC,2,taskCompleteContract);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("工单协议异常");
        }
    }

    /**
     * 封装其他参数
     * @param taskEntity
     */
    private void setparameter(TaskEntity taskEntity,String takeCode) {
        //封装takecode
        taskEntity.setTaskCode(takeCode);
        //封装修改时间及创建时间
        taskEntity.setCreateTime(LocalDateTime.now());
        taskEntity.setUpdateTime(LocalDateTime.now());
        //根据执行人id查询执行人姓名
        UserVO user = userService.getUser(taskEntity.getUserId());
        taskEntity.setUserName(user.getUserName());
        //根据设备编号查询设备信息并封装(区域id,地址)
        VmVO vmInfo = vmService.getVMInfo(taskEntity.getInnerCode());
        taskEntity.setAddr(vmInfo.getNodeAddr());
        taskEntity.setRegionId(vmInfo.getRegionId());

    }

    /**
     * 生成工单编号
     * todo:没看懂redis的操作
     * @return
     */
    private String createTaskCode() {
        //8位年月日字符串
        String data = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        //生成rediskey
        String key = "lkd.task"+data;
        //利用key获取数据
        synchronized (TaskViewModel.class) {
        Object obj = redisTemplate.opsForValue().get(key);

            if (obj == null) {
                redisTemplate.opsForValue().set(key, 1L, Duration.ofDays(1));
                return data+"001";
            }
        }
        return data+Strings.padStart(redisTemplate.opsForValue().increment(key,1).toString(),4,'0');
    }

    /**
     * 检查及校验参数及校验是否有补货操作
     * @param taskViewModel
     */
    private void cheak(TaskViewModel taskViewModel) {

        //1.校验必要参数是否为空
        if (taskViewModel==null)
        {
            throw new RuntimeException("传入的数据有误,请检查");
        }
        if (taskViewModel.getInnerCode()==null||"".equals(taskViewModel.getDesc())||taskViewModel.getDesc()==null)
        {
            throw new RuntimeException("传入的参数有误,请检查");
        }
        //2.校验设备编号是否存在
        VmVO vmInfo = vmService.getVMInfo(taskViewModel.getInnerCode());
        if (vmInfo==null)
        {
            throw new RuntimeException("该设备不存在,请检查");
        }

    }

    /**
     * 补货操作
     * @param details
     */
    private void replenishment(List<TaskDetailsViewModel> details,Long taskId) {
        for (TaskDetailsViewModel detail : details) {
            TaskDetailsEntity taskDetailsEntity = new TaskDetailsEntity();
            BeanUtils.copyProperties(detail,taskDetailsEntity);
            taskDetailsEntity.setTaskId(taskId);
            taskDetailsDao.insert(taskDetailsEntity);
        }
    }

}
